package pl.edu.agh.nn.cp;

import pl.edu.agh.nn.conf.InvalidNetworkConfigurationException;
import pl.edu.agh.nn.grossberg.GrossbergConfiguration;
import pl.edu.agh.nn.grossberg.GrossbergNet;
import pl.edu.agh.nn.kohonen.KohonenConfiguration;
import pl.edu.agh.nn.kohonen.KohonenNet;
import pl.edu.agh.nn.net.AbstractNetWithConfiguration;

public class CounterPropagationNet extends AbstractNetWithConfiguration {

	private KohonenNet kohonenNet;
	private GrossbergNet grossbergNet;
	private CounterPropagationConfiguration configuration;

	public void setConfiguration(CounterPropagationConfiguration configuration) {
		this.configuration = configuration;
	}

	@Override
	public double[] learn(double[] train, double[] test) {
		double kohonenOutput[] = kohonenNet.isLearningFinished() ? kohonenNet.compute(train) : kohonenNet.learn(train,
				null);
		if (kohonenNet.getEpoch() > configuration.getKohonenInitializationEpochs()
				&& !grossbergNet.isLearningFinished()) {
			return grossbergNet.learn(kohonenOutput, test);
		}
		return null;
	}

	@Override
	public double[] compute(double[] input) {
		double[] kohonenOutput = kohonenNet.compute(input);
		return grossbergNet.compute(kohonenOutput);
	}

	@Override
	public void configure() throws InvalidNetworkConfigurationException {
		if (ioConfiguration != null) {
			ioConfiguration.configure();
		}

		KohonenConfiguration kohonenConfiguration = configuration.getKohonenConfiguration();
		kohonenNet = new KohonenNet(kohonenConfiguration);
		kohonenNet.configure();

		GrossbergConfiguration grossbergConfiguration = configuration.getGrossbergConfiguration();
		grossbergConfiguration.setInputDimension(kohonenConfiguration.getPlaneHeight()
				* kohonenConfiguration.getPlaneWidth());
		grossbergNet = new GrossbergNet(grossbergConfiguration);
		grossbergNet.configure();
	}

	@Override
	public boolean isLearningFinished() {
		return kohonenNet.isLearningFinished() && grossbergNet.isLearningFinished();
	}

}
